package com.yedean.factory.support;

import com.yedean.factory.BeansException;
import com.yedean.factory.ObjectFactory;
import com.yedean.factory.config.SingletonRegistry;
import javafx.beans.binding.ObjectExpression;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * DefaultSingletonRegistry 默认的单例注册
 *
 * @author yedean
 * @date 2022/6/28
 */
public class DefaultSingletonRegistry implements SingletonRegistry {
    
    protected static final Object NULL_OBJECT=new Object();

    /**
     * 二级缓存,提前暴露对象 没有完全实例化的对象
     */
    protected final Map<String, Object> earlySingletonObjects=new HashMap<>();
    /**
     * 三级缓存,存放代理对象
     */
    private final Map<String, ObjectFactory<?>> singletonFactories=new HashMap<>();
    
    private final Map<String,DisposableBean> disposableBeans =new HashMap<>();
    
    private final Map<String,Object>  singletonObjects = new HashMap<>();

    @Override
    public Object getSingleton(String name) {
        Object singletonObject = singletonObjects.get(name);
        if (null==singletonObject){
            singletonObject = earlySingletonObjects.get(name);
            if (null==singletonObject){
                ObjectFactory<?> factory = singletonFactories.get(name);
                if (factory!=null){
                    singletonObject=factory.getObject();
                    //把三级缓存中的代理对象中的真是对象获取出来,放入二级缓存中
                    earlySingletonObjects.put(name,singletonObject);
                    singletonFactories.remove(name);
                }
            }
        }
        return singletonObject;
    }

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }


    protected void addSingleton(String name,Object singletonObject){
        singletonObjects.put(name,singletonObject);
    }
    
    
    protected void addSingletonFactory(String beanName,ObjectFactory<?> singletonFactory){
        if (!this.singletonObjects.containsKey(beanName)){
            this.singletonFactories.put(beanName,singletonFactory);
            this.earlySingletonObjects.remove(beanName);
        }
    }


    public void registerDisposableBean(String beanName, DisposableBean bean) {
        disposableBeans.put(beanName, bean);
    }

    public void destroySingletons() {
        Set<String> keySet = this.disposableBeans.keySet();
        Object[] disposableBeanNames = keySet.toArray();

        for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
            Object beanName = disposableBeanNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
